//
// Created by wxd on 2025/7/28.
//
#include <glad/glad.h>
#include "BaseCameraControl.h"
#include <array>

#include "app/Application.h"
#include "GLFW/glfw3.h"

const glm::vec3 BaseCameraControl::worldUp = glm::vec3(0.0f, 1.0f, 0.0f);

BaseCameraControl::~BaseCameraControl() {
    m_EventList.clear();
    m_KeyBoardMap.clear();
}

void BaseCameraControl::onMouse(int button, int action, double xpos, double ypos) {
    bool isPressed = action == GLFW_PRESS;

    // 仅更新第一次按下鼠标的位置
    if (isPressed) {
        m_MouseStatus.downMousePosX = static_cast<float>(xpos);
        m_MouseStatus.downMousePosY = static_cast<float>(ypos);
        m_MouseStatus.curMousePosX = static_cast<float>(xpos);
        m_MouseStatus.downMousePosY = static_cast<float>(ypos);
    }

    switch (button) {
        case GLFW_MOUSE_BUTTON_LEFT:
            m_MouseStatus.isLeftMouseDown = isPressed;
            break;
        case GLFW_MOUSE_BUTTON_MIDDLE:
            m_MouseStatus.isMiddleMouseDown = isPressed;
            break;
        case GLFW_MOUSE_BUTTON_RIGHT:
            m_MouseStatus.isRightMouseDown = isPressed;
            break;
        default:
            break;
    }

    if (m_EnableOutputControlInfo) {
        m_MouseStatus.toString();
    }
}

void BaseCameraControl::onKeyBoard(int key, int action, int mods) {
    if (action == GLFW_REPEAT) {
        return;
    }

    if (key == GLFW_KEY_ESCAPE) {
        glfwSetWindowShouldClose(EngineApp.getCurrentWindow(), true);
        return;
    }

    m_KeyBoardMap[key] = action == GLFW_PRESS;
}

void BaseCameraControl::onCursor(float xpos, float ypos) {
    m_MouseStatus.lastMousePosX = m_MouseStatus.curMousePosX;
    m_MouseStatus.lastMousePosY = m_MouseStatus.curMousePosY;

    m_MouseStatus.curMousePosX = xpos;
    m_MouseStatus.curMousePosY = ypos;

    CameraMoveDirection curHorizonDirection = m_MouseStatus.curMousePosX - m_MouseStatus.lastMousePosX > 0 ? RIGHT : LEFT;
    CameraMoveDirection curVerticalDirection = m_MouseStatus.curMousePosY - m_MouseStatus.lastMousePosY > 0 ? DOWN : UP;

    isVerticalReverse = curVerticalDirection != m_LastVerticalDirection;
    isHorizonRevers = curHorizonDirection != m_LastHorizonDirection;

    m_LastHorizonDirection = curHorizonDirection;
    m_LastVerticalDirection = curVerticalDirection;

    /*Log.msg("BaseCameraControl")
        .param("isVerticaReverse", std::to_string(isVerticalReverse))
        .param("isHorizonRevers", std::to_string(isHorizonRevers)).d();*/
}

void BaseCameraControl::onScroll(double yoffset) {

}

void BaseCameraControl::update() {

}

void BaseCameraControl::forEachControlEvent() const {
    if (m_KeyBoardMap.empty()) return;

    std::ostringstream oss;

    for (const auto keyPair: m_KeyBoardMap) {
        oss << keyPair.first << "->";
    }

    std::cout << oss.str() << "\n";
}

void BaseCameraControl::forEachKeyEvent() const {
    if (m_EventList.empty()) return;

    std::ostringstream oss;

    const size_t size = m_EventList.size();
    for (int i = 0; i < size; i++) {
        if (i < size - 1) {
            oss << ControlEventToString(m_EventList[i]) << "->";
        } else {
            oss << ControlEventToString(m_EventList[i]);
        }
    }

    std::cout << oss.str() << "\n";
}

std::string BaseCameraControl::ControlEventToString(ControlEvent event) {
    static const std::array<std::string, 9> names = {
        "LEFTMOUSEDOWN", "RIGHTMOUSEDOWN", "MIDDLEMOUSEDOWN",
        "LEFTMOUSEUP", "RIGHTMOUSEUP", "MIDDLEMOUSEUP",
        "MOUSEMOVE", "SCROLL", "KEYBOARD"
    };

    const auto index = static_cast<size_t>(event);
    if (index >= names.size()) {
        throw std::out_of_range("Invalid ControlEvent value");
    }
    return names[index];
}

void BaseCameraControl::setEnableControlInfo(const bool enable) {
    m_EnableOutputControlInfo = enable;
}

void BaseCameraControl::setCamera(BaseCamera* camera) {
    m_Camera = camera;
}

void BaseCameraControl::setRotateType(const RotateType type) {
    m_RotateType = type;
}